﻿; (function (global) {

    'use strict';

    // rule: same colors on unit
    //  "-75-469-834629817589--57-4676952481352387146941896375263-48259-98--15--4-54-39-8-"
    // (2 should be removed from 'on' cells starting at 0,0) 

    // rule: can see two colors
    //   "--7-836---397-68--82641975364-19-387-8-367----73-48-6-39-87--267649--1382-863-97-" dual chain of 5 sample !!
    // (5 should be removed from E3)

    //j1 two can see two colors (7) (not from the start :( )
    //"-485913-6-9----8---6--8-5-94-1----58----7--9-----5--3-8---4-165---21-4-3-1436-9--"
    global.Strategies = global.Strategies || {};

    Strategies.SimpleColoring = function SimpleColoring() {
        this.type = 'elimination';
    }

    Strategies.SimpleColoring.prototype.perform = function (grid) {
        for (var k = 1; k < 10; k++) {
            // console.log("k", k);
            var result = this.performOnCandidate(grid, k);
            if (result)
                return result;
        }
        return null;
    }

    Strategies.SimpleColoring.prototype.performOnCandidate = function (grid, candidate) {

        var cells = GridHelper.getCellsOfCandidate(grid, candidate);
        if (cells.length < 4)
            return;

        var chains = [];
        for (var i = 0; i < cells.length; i++) {
            var cell = cells[i];
            if (this.isInChains(cell, chains))
                continue;

            var chain = this.getChain(cell, cells);

            if (chain !== null) {
                chains.push(chain);
            }
        }

        var hasPerformed = false;
        var result = {};
        result.candidate = candidate;
        result.conflicts = [];
        result.seeTwoColors = [];
        for (var i = 0; i < chains.length; i++) {
            var conflictingCells = this.getChainConflitingCells(chains[i]);
            if (conflictingCells.length > 0) {
                SolvingHelper.removeFromOtherCells(candidate, [], conflictingCells);
                result.conflicts.push({ chain: chains[i], conflictingCells: conflictingCells });
                hasPerformed = true;
            }
        }

        for (var i = 0; i < cells.length; i++) {
            for (var c = 0; c < chains.length; c++) {
                var ch = chains[c];
                var ce = cells[i];
                if (this.isInChain(ce, ch))
                    continue;

                if (this.canSeeTwoColors(ce, ch)) {
                    ce.candidates.remove(candidate);
                    result.seeTwoColors.push({ chain: ch, cell: ce });
                    hasPerformed = true;
                }
            }
        }

        if (hasPerformed)
            return result;

        return null;
    }


    Strategies.SimpleColoring.prototype.getChain = function (cell, cells) {
        var linkedCells = this.getLinkedCells(cell, cells);
        if (linkedCells.length === 0)
            return null;

        var on = []
        var off = [];

        on.push(cell);
        off.pushArray(linkedCells);

        for (var i = 0; i < linkedCells.length; i++) {
            var fromCell = linkedCells[i];
            this.getChainRecursive(cells, fromCell, off, on);
        }

        return {
            on: on,
            off: off
        }
    }

    Strategies.SimpleColoring.prototype.getChainRecursive = function (scopeCells, fromCell, on, off) {
        //console.log("rec", fromCell.indices);

        var linkedCells = this.getLinkedCells(fromCell, scopeCells);
        var newLinks = [];
        for (var i = 0; i < linkedCells.length; i++) {
            var linkedCell = linkedCells[i];
            if (!off.contains(linkedCell)) {
                off.push(linkedCell);
                newLinks.push(linkedCell);
            }
        }

        if (!on.contains(fromCell)) {
            on.push(fromCell);
        }

        for (var i = 0; i < newLinks.length; i++) {
            var cell = newLinks[i];
            this.getChainRecursive(scopeCells, cell, off, on);
        }
    }

    Strategies.SimpleColoring.prototype.canSeeTwoColors = function (isolatedCell, chain) {
        return this.isOnSameUnitInGroup(isolatedCell, chain.on)
        && this.isOnSameUnitInGroup(isolatedCell, chain.off)
    }

    Strategies.SimpleColoring.prototype.getChainConflitingCells = function (chain) {
        if (this.isChainGroupConfliting(chain.on))
            return chain.on;

        if (this.isChainGroupConfliting(chain.off))
            return chain.off;

        return [];
    }

    Strategies.SimpleColoring.prototype.isChainGroupConfliting = function (chainGroupCells) {
        var chainGroupCellsCopy = chainGroupCells.slice(0);
        while (chainGroupCellsCopy.length > 0) {
            var cell = chainGroupCellsCopy.pop();
            if (this.isOnSameUnitInGroup(cell, chainGroupCellsCopy))
                return true;
        }
        return false;
    }

    Strategies.SimpleColoring.prototype.isOnSameUnitInGroup = function (cell, chainGroupCells) {
        for (var i = 0; i < chainGroupCells.length; i++) {
            if (SolvingHelper.IsOnSameUnitAs(cell, chainGroupCells[i]))
                return true;
        }
        return false;
    }

    Strategies.SimpleColoring.prototype.isInChains = function (cell, chains) {
        for (var i = 0; i < chains.length; i++) {
            if (this.isInChain(cell, chains[i]))
                return true;
        }
        return false;
    }

    Strategies.SimpleColoring.prototype.isInChain = function (cell, chain) {
        return chain.on.contains(cell) || chain.off.contains(cell)
    }

    Strategies.SimpleColoring.prototype.getLinkedCells = function (cell, cells) {
        var onSameRow = [];
        var onSameColumn = [];
        var onSameRegion = [];

        var regionId = RegionHelper.computedRegions[cell.indices.i][cell.indices.j];

        for (var i = 0; i < cells.length; i++) {
            var otherCell = cells[i];
            if (otherCell === cell)
                continue;

            if (cell.indices.i === otherCell.indices.i) {
                onSameRow.push(otherCell);
            }

            if (cell.indices.j === otherCell.indices.j) {
                onSameColumn.push(otherCell);
            }

            var otherRegionId = RegionHelper.computedRegions[otherCell.indices.i][otherCell.indices.j];
            if (regionId === otherRegionId) {
                onSameRegion.push(otherCell);
            }
        }

        var links = [];

        if (onSameRow.length === 1)
            links.push(onSameRow[0]);

        if (onSameColumn.length === 1)
            links.push(onSameColumn[0]);

        if (onSameRegion.length === 1 && !links.contains(onSameRegion[0]))
            links.push(onSameRegion[0]);

        return links;
    }

}(this));
